﻿#region usings
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.IO.IsolatedStorage;
using System.Threading;
using System.Windows;
using InsuranceAdjuster.OccasionallyConnected.Messages;
using InsuranceAdjuster.Services;
#endregion
namespace InsuranceAdjuster.OccasionallyConnected.CacheMonitors {
    public class PollingCacheMonitor : ICacheMonitor {
        #region Message Loop
        public void Start() {
            _BackgroundCacheUpdateThread.Start();
        }

        public void Stop() {
            _IsRunning = false;
        }

        private void RunBackgroundCacheUpdater() {
            _IsRunning = true;

            while (_IsRunning) {
                ExecuteSync();
                Thread.Sleep(_syncInterval);
            }
        }

        #endregion

        #region Sync Groups
        private void SyncReferenceData() {
            EntityManager.Current.ProcessMessage(new SyncClaimStatusesMessage(), true);
            EntityManager.Current.ProcessMessage(new SyncStatesMessage(), true);
            EntityManager.Current.ProcessMessage(new SyncVehicleInformationMessage(), true);
            //EntityManager.Current.ProcessMessage(new SyncStandardVehicleImagesMessage(), true);
        }

        private void SyncActivityData() {
            EntityManager.Current.ProcessMessage(new SyncAppointmentsMessage(), true);
            EntityManager.Current.ProcessMessage(new SyncClaimsMessage(), true);
            EntityManager.Current.ProcessMessage(new SyncClaimDamagesMessage(), true);
        }

       
        #endregion

        #region Sync Ops
        public void SyncNow() {
            Debug.WriteLine("Sync Now");
            _LastActivityUpdateTime = DateTime.MinValue;
            _LastReferenceUpdateTime = DateTime.MinValue;

            ThreadPool.QueueUserWorkItem(x => ExecuteSync());
        }
        private void ExecuteSync() {
            lock (_SyncLock) {
                if (!EntityManager.Current.IsOnline || _isSynching)
                    return;

                try {
                    _isSynching = true;

                    // Activity Data
                    if (_LastActivityUpdateTime.AddSeconds(ActivitySyncIntervalInSeconds) < DateTime.UtcNow) {;
                        SyncActivityData();
                        LastActivityUpdateTime = DateTime.UtcNow;
                    }

                    // Reference Data
                    if (_LastReferenceUpdateTime.AddSeconds(ReferenceSyncIntervalInSeconds) < DateTime.UtcNow) {
                        SyncReferenceData();
                        LastReferenceUpdateTime = DateTime.UtcNow;
                    }
                }
                finally {
                    _isSynching = false;
                }
            } // lock
        }
        #endregion

        #region Initilization
        public PollingCacheMonitor() {
            _BackgroundCacheUpdateThread = new Thread(new ThreadStart(RunBackgroundCacheUpdater));
            _BackgroundCacheUpdateThread.Name = "BackgroundCacheUpdateThread";
        }

        public void Initialize(EntityManager manager) {
            _syncInterval = 1000;
            _EntityManager = manager;
            _LastActivityUpdateTime = DateTime.UtcNow;
            _LastReferenceUpdateTime = DateTime.UtcNow;
        }
        private int _syncInterval;
        private bool _isSynching = false;
        private Object _SyncLock = new Object();
        private Thread _BackgroundCacheUpdateThread = null;
        private EntityManager _EntityManager = null;

        private IInsuranceAdjusterDataService GetDataService() {
            return new InsuranceAdjusterDataService();
        }
        #endregion
        
        #region Properties
        private Boolean _IsRunning = false;
        public Boolean IsRunning {
            get { return _IsRunning; }
        }

        public double ActivitySyncIntervalInSeconds {
            get { return ( (TimeSpan) IsolatedStorageSettings.ApplicationSettings["ActivityUpdateInterval"]).TotalSeconds; }
            set {
                if (((TimeSpan)IsolatedStorageSettings.ApplicationSettings["ActivityUpdateInterval"]).TotalSeconds == value)
                    return;
                IsolatedStorageSettings.ApplicationSettings["ActivityUpdateInterval"] = new TimeSpan(0, 0, (int)value);
                RaisePropertyChanged("ActivitySyncIntervalInSeconds");
            }
        }
        
        public double ReferenceSyncIntervalInSeconds {
            get { return ((TimeSpan)IsolatedStorageSettings.ApplicationSettings["ReferenceUpdateInterval"]).TotalSeconds; }
            set {
                if (((TimeSpan)IsolatedStorageSettings.ApplicationSettings["ReferenceUpdateInterval"]).TotalSeconds == value)
                    return;
                IsolatedStorageSettings.ApplicationSettings["ReferenceUpdateInterval"] = new TimeSpan(0, 0, (int)value);
                RaisePropertyChanged("ReferenceSyncIntervalInSeconds");
            }
        }

        private DateTime _LastActivityUpdateTime = DateTime.MinValue;
        public DateTime LastActivityUpdateTime {
            get { return _LastActivityUpdateTime; }
            private set {
                if (_LastActivityUpdateTime != value) {
                    _LastActivityUpdateTime = value;
                    RaisePropertyChanged("LastActivityUpdateTime");
                }
            }
        }

        private DateTime _LastReferenceUpdateTime = DateTime.MinValue;
        public DateTime LastReferenceUpdateTime {
            get { return _LastReferenceUpdateTime; }
            private set {
                if (_LastReferenceUpdateTime != value) {
                    _LastReferenceUpdateTime = value;
                    RaisePropertyChanged("LastReferenceUpdateTime");
                }
            }
        }
        
        #endregion

        #region INotifyPropertyChanged

        public event PropertyChangedEventHandler PropertyChanged;
        protected void RaisePropertyChanged(string propertyName) {
            if (PropertyChanged == null)
                return;
            Deployment.Current.Dispatcher.BeginInvoke(() => PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName)));
        }
        #endregion
    }
}
